package quarto.test;

import java.util.Scanner;
import quarto.model.Board;
import quarto.model.InvalidPieceValueException;
import quarto.model.Piece;

/**
 * Klasse voor het onderhouden van een Quarto Game.
 * @author  Frank Borgonjen & Tim Smit
 */
public class TextGame 
{
    public static final int AANTAL_PLAYERS = 2;

    /**
     * Het speelbord. 
     * @invariant bord != null
     */
    private Board board;       

    /**
     * De twee spelers van het spel.
     * @invariant spelers.length == AANTAL_PLAYERS,
     *            spelers[0] != null, spelers[1] != null
     */
    private String[] players;

    /** 
     * Index van huidige player. 
     * @invariant 0 <= huidig < AANTAL_PLAYERS
     */
    private int huidig;  

    // het huidige stuk
    private Piece currentPiece; 
    
    private Scanner input;
    
    public static void main(String[] args)
    {
        new TextGame("Speler 1", "Speler 2");
    }
    
    /**
     * Construeert een nieuw TextGame object.
     * @param   s0 naam van de eerste Speler
     * @param   s1 naam de tweede Speler
     * @require <code>s0 != null && s1 != null</code>
     */
    public TextGame(String s0, String s1) 
    {
        board      = new Board();
        players    = new String[AANTAL_PLAYERS];
        players[0] = s0;
        players[1] = s1;
        huidig     = 0;
        input      = new Scanner(System.in);
        
        reset();
        start();
    }

    /**
     * Start het Quarto spel.
     * Vraagt na elk beeindigd spel of er doorgespeeld moet worden.
     * Blijft doorspelen totdat de gebruikers niet meer willen spelen.
     */
    public void start() 
    {
        boolean doorgaan = true;
        while (doorgaan) 
        {
            reset();
            play();
            doorgaan = leesBoolean("\n> Nog een keer (j/n)?", "j", "n");
        }
    }
    
    /**
     * Stelt de gebruiker een vraag waarop ja (true) of nee (false) kan
     * worden geantwoord. Als de ingelezen String overeenkomt met de parameter 
     * ja wordt true opgeleverd en als de String overeenkomt met de parameter 
     * nee wordt false opgeleverd. In alle andere gevallen wordt de vraag 
     * nogmaals gesteld. De methode eindigt pas als ofwel het ja-antwoord 
     * ofwel\het nee-antwoord is gegeven.
     * @parom  prompt de vraag die gesteld wordt
     * @param  ja  de String de correspondeert met het ja-antwoord
     * @param  nee de String de correspondeert met het nee-antwoord
     * @return true als het ja-antwoord is ingetypt, 
     *         false als het nee-antwoord is ingetypt.
     */
    private boolean leesBoolean(String prompt, String ja, String nee) 
    {
        String antwoord; 
        do 
        {
            System.out.print(prompt);
            antwoord = input.hasNextLine() ? input.nextLine() : null;
        } 
        while ( antwoord == null ||
              (!antwoord.equals(ja) && !antwoord.equals(nee)));                  
        return antwoord.equals(ja);
    }
    
    
    private int leesInt(String prompt) 
    {
        int res = -1;
        do 
        {
            System.out.print(prompt);        
            res   = input.hasNextInt() ? input.nextInt() : -1;
        } 
        while (res == -1);
        return res;
    }
    
    /**
     * Reset dit spel. <br>
     * Het speelbord wordt leeggemaakt en players[0] wordt de huidige speler.
     */
    private void reset() 
    {
        huidig = 0;
        currentPiece = new Piece(0,1,1,0); 
        board.reset();
    }

    /**
     * Speelt een Quarto spel. <br>
     * Eerst wordt het (nog lege) speelbord getoond.
     * Daarna wordt er doorgespeeld totdat het spel afgelopen is.
     * De spelers mogen om-en-om een zet doen.
     * Na elke zet wordt het veranderde speelbord getoond.
     */
    private void play() 
    {
    	// bord laten zien
    	update();
    	
        int pos;
        int piece;
        Piece p;
    	while (!board.gameOver())
    	{
            System.out.println("Huidige stuk: " + this.currentPiece.getDescription());
            pos = -1;
            do
            {
                pos = leesInt(players[huidig] + ", op welke positie wil je het huidige stuk hebben? (0 t/m 15)\n> ");
                if (!board.isEmpty(pos) || pos < 0 || pos > 15)
                {
                    System.out.println("Positie is niet geldig of niet leeg");
                    pos = -1;
                }
            }
            while (pos == -1);
    		this.board.setPiece(pos, currentPiece);
            
            if (!board.gameOver())
            {
                p = null;
                do
                {
                    try
                    {
                        piece = leesInt(players[huidig] + ", geef het stuk voor de tegenstander (0 t/m 15)\n> ");
                        p = new Piece(piece);
                        if (!board.isAvailablePiece(p))
                        {
                            System.out.println("Dit stuk is niet meer beschikbaar");
                            p = null;
                        }
                    }
                    catch (InvalidPieceValueException e)
                    {
                        System.out.println("ongeldige piece: "+e.getMessage());
                    }
                }
                while (p == null || !board.isAvailablePiece(p));

                // huidige piece updaten
                currentPiece = p;

                // huidige speler updaten
                huidig = (huidig + 1) % AANTAL_PLAYERS;
            }
            
            // bord laten zien
            update();
    	}
		// spel is klaar, uitslag laten zien
		schrijfUitslag();
    }

    /**
     * Schrijft de toestand van het spel naar de standaarduitvoer.
     */
    private void update() 
    {
        System.out.println("\nHuidige toestand: \n\n"+ board.toString()+"\n");
    }

    /**
     * Schrijft de uitslag van het spel naar de standaarduitvoer.
     * @require board.gameOver()
     */
    private void schrijfUitslag() 
    {
		if (board.hasWinner())
		{
			System.out.println("Speler "+players[huidig]+" heeft gewonnen");
		}
		else 
		{
            System.out.println("Er is geen winnaar -> remise");
        }
    }
} // end of class Spel
